CognitoUserPoolsを使うAngular2 SPAのサンプルを動かす
丹内です。Public Betaになってしばらく経つCognito UserPoolsですが、そのサンプルアプリを見つけたので動かして観察してみます。
Cognito UserPoolsとは
Amazon Cognitoは、モバイルアプリやSPA(Single Page Application)など信頼できない環境で動作するAWS SDKに対して、クレデンシャルの安全な発行を行うためのサービスです。ユーザ認証とクレデンシャル発行(Cognito Identity)、ユーザデータ管理(Cognito Sync)の機能を有しています。
そんなCognitoに先日追加された機能が、Cognito UserPoolsです。
[新機能] Amazon Cognito に待望のユーザー認証基盤「User Pools」が追加されました!
UserPools以前のCognito(Cognito Federated Identity)では、Authentication providersとしてOIDC IdPやSAMLを利用することができました。
UserPoolsによって、Authentication providersにCognitoが管理する、メールアドレスとパスワードにより認証されるIdentityも利用可能となりました。
大抵のアプリケーションではメールアドレスとパスワードで認証されるユーザ管理機能が付いていると思いますが、UserPoolsによりフルマネージドな機能が提供されます。さらに、クライアントにAWSリソースを操作するクレデンシャルを安全に付加することができるので、クライアントから直接AWSを操作することで、サーバ側の負荷を減らすことも行いやすくなります。
セットアップ
今回動かすサンプルアプリのリポジトリは以下になります。
awslabs/aws-cognito-angular2-quickstart
READMEに沿ってセットアップしていきます。
$ git clone --depth 1 [email protected]:awslabs/aws-cognito-angular2-quickstart.git $ cd aws-cognito-angular2-quickstart $ npm install $ bower install
が、Macの場合はsedのオプションが異なるためAWSリソース作成スクリプトが動作しません。 そこで、シェルスクリプトを以下のdiffのように編集します。
diff --git a/aws/createResources.sh b/aws/createResources.sh index b96b7ed..aa4f2bb 100755 --- a/aws/createResources.sh +++ b/aws/createResources.sh @@ -1,6 +1,11 @@ #!/usr/bin/env bash -ROOT_NAME=DevDay +if [ $# -ne 1 ]; then + echo "usage: createResources.sh [name]" + exit 1 +fi + +ROOT_NAME=$1 BUCKET_NAME=budilov-$ROOT_NAME TABLE_NAME=LoginTrail$ROOT_NAME ROLE_NAME_PREFIX=$ROOT_NAME @@ -44,12 +49,12 @@ aws iam put-role-policy --role-name $ROLE_NAME_PREFIX-authenticated-role --polic # Create the user pool aws cognito-idp create-user-pool --pool-name $POOL_NAME --policies file://user-pool-policy.json --region $REGION > /tmp/$POOL_NAME-create-user-pool -userPoolId=$(grep -Po '"Id":.*?[^\\]",' /tmp/$POOL_NAME-create-user-pool | awk -F'"' '{print $4}') +userPoolId=$(perl -nle 'print $& if m{"Id":.*?[^\\]",}' /tmp/$POOL_NAME-create-user-pool | awk -F'"' '{print $4}') echo "Created user pool with an id of " $userPoolId # Create the user pool client aws cognito-idp create-user-pool-client --user-pool-id $userPoolId --no-generate-secret --client-name webapp --region $REGION > /tmp/$POOL_NAME-create-user-pool-client -userPoolClientId=$(grep -Po '"ClientId":.*?[^\\]",' /tmp/$POOL_NAME-create-user-pool-client | awk -F'"' '{print $4}') +userPoolClientId=$(perl -nle 'print $& if m{"ClientId":.*?[^\\]",}' /tmp/$POOL_NAME-create-user-pool-client | awk -F'"' '{print $4}') echo "Created user pool client with id of " $userPoolClientId
また、AWSアカウントIDも書き換えておく必要があります。
diff --git a/aws/authrole.json b/aws/authrole.json index df27aeb..6806522 100644 --- a/aws/authrole.json +++ b/aws/authrole.json @@ -23,7 +23,7 @@ "dynamodb:DeleteItem" ], "Resource": [ - "arn:aws:dynamodb:us-east-1:540403165297:table/TABLE_NAME" + "arn:aws:dynamodb:us-east-1:012345678901:table/TABLE_NAME" ], "Condition": { "ForAllValues:StringEquals": {
その上で、以下のように実行します。
$ aws/createResources.sh mycognitosample
READMEにも記載されていますが、シェルスクリプト実行時にCognito IdentityへのRoleの設定がエラーになってしまうので、リソース作成完了後に自分で設定する必要があります。
このシェルスクリプトで作成される主要なリソースは、以下のとおりです。us-east-1に作成されます。
- Cognito UserPool
- Cognito Federated Identity Pool
- DynamoDBテーブル(アクセスログ機能用、RCU1/WCU1、Estimated cost $0.59/month)
- IAMロール(authenticatedとunauthenticatedの2つ)
authenticated roleのポリシーは以下のとおりです。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "mobileanalytics:PutEvents", "cognito-sync:*", "cognito-identity:*" ], "Resource": [ "*" ] }, { "Effect": "Allow", "Action": [ "dynamodb:GetItem", "dynamodb:BatchGetItem", "dynamodb:Query", "dynamodb:PutItem", "dynamodb:UpdateItem", "dynamodb:DeleteItem" ], "Resource": [ "arn:aws:dynamodb:us-east-1:012345678:table/LoginTrailmycognitosample" ], "Condition": { "ForAllValues:StringEquals": { "dynamodb:LeadingKeys": [ "${cognito-identity.amazonaws.com:sub}" ] } } } ] }
このIAMロールのTrust Relationshipは以下のとおりです。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "cognito-identity.amazonaws.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "cognito-identity.amazonaws.com:aud": "us-east-1:aaaa-bbbb-cccc-dddd" }, "ForAnyValue:StringLike": { "cognito-identity.amazonaws.com:amr": "authenticated" } } } ] }
動作確認
READMEに沿って、ハードコードされたAWSリソースの値を変更します。
diff --git a/src/app/service/aws.service.ts b/src/app/service/aws.service.ts index 59b17cb..0cb86b6 100644 --- a/src/app/service/aws.service.ts +++ b/src/app/service/aws.service.ts @@ -117,7 +117,7 @@ export class DynamoDBService { static getLogEntries(mapArray:Array<Stuff>) { var params = { - TableName: 'LoginTrail', + TableName: 'LoginTrailmycognitosample', KeyConditionExpression: "userId = :userId", ExpressionAttributeValues: { ":userId": AWS.config.credentials.params.IdentityId @@ -147,7 +147,7 @@ export class DynamoDBService { static write(data:string, date:string, type:string):void { DynamoDBService.DDB = new AWS.DynamoDB({ - params: {TableName: 'LoginTrail'} + params: {TableName: 'LoginTrailmycognitosample'} }); diff --git a/src/app/service/cognito.service.ts b/src/app/service/cognito.service.ts index a720d23..b2ef4de 100644 --- a/src/app/service/cognito.service.ts +++ b/src/app/service/cognito.service.ts @@ -24,9 +24,9 @@ export class CognitoUtil { public static _REGION = "us-east-1"; - public static _IDENTITY_POOL_ID = "us-east-1:fbe0340f-9ffc-4449-a935-bb6a6661fd53"; - public static _USER_POOL_ID = "us-east-1_PGSbCVZ7S"; - public static _CLIENT_ID = "hh5ibv67so0qukt55c5ulaltk"; + public static _IDENTITY_POOL_ID = "us-east-1:aaaa-bbbb-ccccc-dddd"; + public static _USER_POOL_ID = "us-east-1_AAAABBBBCCCC"; + public static _CLIENT_ID = "aaaabbbbccccdddd11112222333"; public static _POOL_DATA = { UserPoolId: CognitoUtil._USER_POOL_ID, @@ -108,7 +108,7 @@ export class CognitoUtil { export class UserRegistrationService { constructor(@Inject(CognitoUtil) public cognitoConfigs:CognitoUtil) { - + AWSCognito.config.update({accessKeyId: 'anything', secretAccessKey: 'anything'}); } register(user:RegistrationUser, callback:CognitoCallback):void {
READMEの修正だけだと実行時にエラーが出てうまく動かなかったので、AWSCognito.config.update({accessKeyId: 'anything', secretAccessKey: 'anything'});
を加えています。
参考:User Pools for Amazon Cognito - CredentialsError: Missing credentials in config
また、ローカルで実行する前に、Cognito UserPoolsの設定を変更しておく必要があります。この設定変更によって、アカウント作成時の確認メールが送信されます。
そして実行します。
$ npm start > [email protected] start /Users/tannai.yuki/.ghq/github.com/awslabs/aws-cognito-angular2-quickstart > ng server Livereload server on http://localhost:49152 Serving on http://localhost:4200/ Build successful - 2422ms. Slowest Trees | Total ----------------------------------------------+--------------------- BroccoliTypeScriptCompiler | 1528ms vendor | 627ms Slowest Trees (cumulative) | Total (avg) ----------------------------------------------+--------------------- BroccoliTypeScriptCompiler (1) | 1528ms vendor (1) | 627ms
localhost:4200にアクセスして、アカウントを作成してみます。
アカウント作成直後のUserPoolsの画面が以下です。User StatusがUnauthenticatedになっています。
少し待つと登録メールアドレスに確認コードが送信されてくるので、それをブラウザから入力すると以下のように値が変化します。
改めてログインすると、DynamoDBに履歴が格納され、それをアプリから参照することができます。
この履歴はログイン・ログアウト時にDynamoDBに格納され、それを参照しています。
Federated IdentityのAuthentication Providerに、UserPoolが追加されていることがわかります。
まとめ
サンプルを利用して、Cognito UserPoolsが実際に動く様子を確認することができました。
Angular2のサンプルとしても良いコードだと思うので、みなさんもぜひ動かしてみてください。